import {isStr, isVNode, isObj} from "../utils.js";
import {createEmptyVnode} from "../vnode/main.js";
import {compileToFunction} from "../Compiler.js";
import initRender from '../init/initRender.js'
import Watcher from "../watchAndDep/Watcher.js";
import initState from '../state.js'

function initProxyData(vm, key, data){
    for(let i in data){
        Object.defineProperty(vm, i, {
            get(){
                return vm[key][i]
            },
            set(newVal){
                vm[key][i] = newVal
            }
        })
    }
}

var uid$3 = 0;

function init(options){
    let vm = this;
    vm.$options = options

    vm._uid = uid$3++

    vm.self = vm

    console.log('trggger init method')

    let data = options.data
    vm.$data = typeof data === 'function' ? data() : data || {}

    initProxyData(vm, '$data', data)

    // initLifecycle(vm);
    // initEvents(vm);
    initRender(vm);
    // callHook(vm, 'beforeCreate');
    // initInjections(vm); // resolve injections before data/props
    initState(vm);

    // initProvide(vm); // resolve provide after data/props
    // callHook(vm, 'created');

    if (vm.$options.el) {
        vm.$mount(vm.$options.el);
    }
    return vm
}

function mountComonent(vm, el){
  vm.$el = el
  let updateComponent = function(){
      vm._update(vm._render())
  }

  new Watcher(vm, updateComponent)
}

function _render(vm, el){

    let options = vm.$options
    let vnode = null
    if(options.render && typeof options.render === 'function'){
        let res = options.render()
        vnode = isVNode(res) ? res : createEmptyVnode();
    }else{
        let render;
        if(options.template && isStr(options.template) && options.template.chartAt(0) !== '#'){
            render = compileToFunction(options.template).render
        }else{
            render = compileToFunction(vm.$el.outerHTML).render;
        }
        vnode = render.call(vm);
    }
    if(!isVNode(vnode)){
        throw new TypeError('无法挂载实例， 请查证后再试')
    }
}

export default function initMixin (Vue) {
    Vue.prototype.$mount = function(el){
        el = document.querySelector(el)

        return mountComonent(this, el)
    }
    Vue.prototype._init = init
}
